/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.logging.filter.access;

import com.aduib.boot.common.concurrent.NameThreadLocal;
import com.aduib.boot.common.log.LOG;
import com.aduib.boot.common.servlet.CachedContentServletRespWrapper;
import com.aduib.boot.logging.access.handler.AccessLogHandler;
import com.aduib.boot.logging.filter.AbstractLogFilter;
import org.springframework.util.AntPathMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @description: AccessLogFilter
 * @author: zzh
 * @date: 2021/9/15 17:07
 */
public class AccessLogFilter extends AbstractLogFilter {

  private final AccessLogHandler<?> accessLogHandler;

  private final List<String> ignoreUrlPatterns;

  private static final NameThreadLocal<Long> TIMETHREADLOCAL=new NameThreadLocal<Long>(AccessLogFilter.class.getName()+"#1");

  private static final AntPathMatcher ANTPATHMATCHER=new AntPathMatcher();

  public AccessLogFilter(AccessLogHandler<?> accessLogHandler,List<String> ignoreUrlPatterns) {
    this.ignoreUrlPatterns = ignoreUrlPatterns;
    this.accessLogHandler=accessLogHandler;
  }

  @Override
  public boolean beforeRequest(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain)
      throws ServletException, IOException {
    // 跳过部分忽略 url
    String requestUri = request.getRequestURI();
    for (String ignoreUrlPattern : ignoreUrlPatterns) {
      if (ANTPATHMATCHER.match(ignoreUrlPattern, requestUri)) {
        filterChain.doFilter(request, response);
        return false;
      }
    }
    TIMETHREADLOCAL.getThreadLocal().set(System.currentTimeMillis());
    return true;
  }

  @Override
  public void afterRequest(HttpServletRequest request, HttpServletResponse response,
      Throwable  myThrowable) throws ServletException, IOException {

    // 结束时间
    Long endTime = System.currentTimeMillis();
    // 执行时长
    Long executionTime = endTime - (TIMETHREADLOCAL.getThreadLocal().get());
    // 记录在doFilter里被程序处理过后的异常，可参考
    // http://www.runoob.com/servlet/servlet-exception-handling.html
    Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
    if (throwable != null) {
      myThrowable = throwable;
    }
    // 生产一个日志并记录
    try {
      accessLogHandler.handleLog(request, response, executionTime, myThrowable);
    }
    catch (Exception e) {
      LOG.e("logging access_log error!", e);
    }
    // 重新写入数据到响应信息中
    ((CachedContentServletRespWrapper)response).copyBodyToResponse();

  }


}
